const transfer = {}
const { Server } = require('socket.io')
const socketioJwt = require('socketio-jwt')
const redis = require('../config/redis.js')
const db = require('../config/database.js')
const code = require('../config/code.js')
const User = require('../model/user.js')
const PPT = require('../model/ppt.js')

transfer.getSocketio = function (server) {
  const io = new Server(server, {
    cors: {
      origin: '*'
    }
  })
  io.use(
    socketioJwt.authorize({
      secret: 'leazerfspacejwt20220503',
      handshake: true,
      auth_header_required: true,
      callback: 15000
    })
  )
  // io.use(async (socket, next) => {
  //   const roomId = socket.handshake.query.roomId
  //   const roomKey = 'room' + roomId
  //   if (await redis.exists(roomKey) === 0) {
  //     return next(new Error('没有此会议'))
  //   }
  //   next()
  // })

  io.on('connection', (socket) => {
    handleConnection(io, socket)

    socket.on('disconnect', async () => {
      console.log('断开')
      const userId = socket.decoded_token.id
      const roomId = socket.handshake.query.roomId
      const roomKey = 'room' + roomId
      await redis.hDel('user' + userId, roomId)
      if (await redis.exists(roomKey) === 0) {
        return
      }
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      delete member[userId]
      const volumePeer = JSON.parse(await redis.hGet(roomKey, 'volumePeer'))
      delete volumePeer[userId]
      await redis.multi()
              .hSet(roomKey, 'member', JSON.stringify(member))
              .hSet(roomKey, 'volumePeer', JSON.stringify(volumePeer))
              .exec()
      socket.to(roomKey).emit('other leave room', {
        userId: userId,
        member: member,
        volumePeer: volumePeer
      })
    })

    socket.on('close room', async () => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      io.to(roomKey).emit('receive close room', '会议已结束')
      for (const x in member) {
        await redis.del('user' + x.id)
      }
      await redis.multi()
              .del(roomKey)
              .del('owner' + userId)
              .exec()
    })

    socket.on('send msg', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      if (!member[userId]) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '该房间没有此用户'
        })   
      }
      const chatMsg = JSON.parse(await redis.hGet(roomKey, 'chatMsg'))  
      chatMsg.push({
        realname: member[userId].realname,
        userId: userId,
        msg: msg,
        time: Date.now()
      })
      await redis.hSet(roomKey, 'chatMsg', JSON.stringify(chatMsg))
      io.to(roomKey).emit('receive chat msg', chatMsg)
    })

    socket.on('ban all volume', async () => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const owner = JSON.parse(await redis.hGet(roomKey, 'owner'))
      if (userId !== owner.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有禁止用户发言的权限'
        })        
      }
      const volumePeer = JSON.parse(await redis.hGet(roomKey, 'volumePeer'))
      for (const x in volumePeer) {
        io.to(volumePeer[x]).emit('receive ban volume')
      }
    })

    socket.on('ban volume', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const owner = JSON.parse(await redis.hGet(roomKey, 'owner'))
      if (userId !== owner.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有禁止用户发言的权限'
        })        
      }
      io.to(msg.socketId).emit('receive ban volume')
    })

    socket.on('sendpeer volume up', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const volumePeer = JSON.parse(await redis.hGet(roomKey, 'volumePeer'))
      if (Object.keys(volumePeer).length >= 5) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '同时可发言人数不能超过5人'
        })
      }
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      member[userId].volumeUp = true
      volumePeer[userId] = member[userId].socketId
      await redis.multi()
              .hSet(roomKey, 'member', JSON.stringify(member))
              .hSet(roomKey, 'volumePeer', JSON.stringify(volumePeer))
              .exec()
      socket.emit('self receive sendpeer volume up', {
        member: member,
        volumePeer: volumePeer        
      })
      socket.to(roomKey).emit('receive sendpeer volume up', {
        member: member,
        volumePeer: volumePeer
      })
    })

    socket.on('sendpeer volume off', async () => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      member[userId].volumeUp = false
      const volumePeer = JSON.parse(await redis.hGet(roomKey, 'volumePeer'))
      delete volumePeer[userId]
      await redis.multi()
              .hSet(roomKey, 'member', JSON.stringify(member))
              .hSet(roomKey, 'volumePeer', JSON.stringify(volumePeer))
              .exec()
      io.to(roomKey).emit('receive sendpeer volume off', {
        member: member,
        volumePeer: volumePeer
      })
    })

    socket.on('peer msg', async (msg) => {
      const roomKey = 'room' + socket.handshake.query.roomId
      if (msg.type === 'offer') {
        io.to(msg.toSocketId).emit('peer msg', msg)
      } else if (msg.type === 'answer') {
        io.to(msg.toSocketId).emit('peer msg', msg)
      } else if (msg.type === 'candidate') {
        io.to(msg.toSocketId).emit('peer msg', msg)
      }  
    })

    socket.on('kick user', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const owner = JSON.parse(await redis.hGet(roomKey, 'owner'))
      if (userId !== owner.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有踢出成员的权限'
        })        
      }
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      if (!member[msg.id]) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '该房间没有此用户'
        })   
      }
      delete member[msg.id]
      await redis.hSet(roomKey, 'member', JSON.stringify(member))
      io.to(roomKey).emit('receive kick user', {
        member: member,
        user: msg
      })
      io.to(msg.socketId).emit('receive self kick', msg)
    })
    // 指定为放映者
    socket.on('change master', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const owner = JSON.parse(await redis.hGet(roomKey, 'owner'))
      if (userId !== owner.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有切换放映者的权限'
        })        
      }
      const member = JSON.parse(await redis.hGet(roomKey, 'member'))
      if (!member[msg.id]) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '该房间没有此用户'
        })   
      }
      await redis.hSet(roomKey, 'master', JSON.stringify(member[msg.id]))
      io.to(roomKey).emit('receive master', member[msg.id])
    })

    socket.on('undo line', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const master = JSON.parse(await redis.hGet(roomKey, 'master'))
      if (userId !== master.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有操作画板的权限'
        })        
      }
      const drawCanv = JSON.parse(await redis.hGet(roomKey, 'drawCanv'))
      drawCanv.objects.pop()
      await redis.hSet(roomKey, 'drawCanv', JSON.stringify(drawCanv))
      io.to(roomKey).emit('receive undo line', msg)
    })

    socket.on('draw line', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const master = JSON.parse(await redis.hGet(roomKey, 'master'))
      if (userId !== master.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有操作画板的权限'
        })        
      }
      const drawCanv = JSON.parse(await redis.hGet(roomKey, 'drawCanv'))
      drawCanv.objects.push(msg)
      await redis.hSet(roomKey, 'drawCanv', JSON.stringify(drawCanv))
      io.to(roomKey).emit('receive draw line', msg)
    })

    socket.on('change page', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const pptPage = msg.pptPage
      const master = JSON.parse(await redis.hGet(roomKey, 'master'))
      if (userId !== master.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有操作ppt的权限'
        })        
      }
      await redis.hSet(roomKey, 'pptPage', pptPage)
      socket.to(roomKey).emit('receive page', {
        pptPage: pptPage
      })
    })

    socket.on('change ppt', async (msg) => {
      const userId = socket.decoded_token.id
      const roomKey = 'room' + socket.handshake.query.roomId
      const pptId = msg.pptId
      const master = JSON.parse(await redis.hGet(roomKey, 'master'))
      if (userId !== master.id) {
        return socket.emit('throw err', {
          code: code.err,
          msg: '没有操作ppt的权限'
        })        
      }
      const [errFind, resFind] = await db.query(PPT.findPPTById, [userId, pptId])
      if (errFind) {
        return socket.emit('throw err', {
          code: code.dbErr,
          msg: '切换文档失败'
        })         
      }
      if (resFind.length === 0) {
        return socket.emit('throw err', {
          code: code.dbErr,
          msg: '切换文档失败'
        })  
      }
      await redis.multi()
        .hSet(roomKey, 'pptId', pptId)
        .hSet(roomKey, 'pptPage', 0)
        .hSet(roomKey, 'ppt', JSON.stringify(resFind[0]))
        .exec()
      
      io.to(roomKey).emit('receive ppt', {
        pptId: pptId,
        pptPage: 0,
        ppt: JSON.stringify(resFind[0])
      })
    })
  })

}

function handleConnection(io, socket) {
  (async () => {
    console.log('连接')
    const userId = socket.decoded_token.id
    const roomKey = 'room' + socket.handshake.query.roomId
    if (await redis.exists('user' + userId) !== 0) {
      return socket.emit('throw err', {
        code: code.err,
        msg: '此用户已加入别的会议'
      })
    }
    if (await redis.exists(roomKey) === 0) {
      return socket.emit('throw err', {
        code: code.noRoomErr,
        msg: '不存在此会议'
      })
    }
    const member = JSON.parse(await redis.hGet(roomKey, 'member'))
    if (Object.keys(member).length >= 100) {
      return socket.emit('throw err', {
        code: code.roomFullErr,
        msg: '此会议人数已满100，加入失败'
      })
    }
    const [errFind, resFind] = await db.query(User.findAllById, [userId])
    if (errFind) {
      return socket.emit('throw err', {
        code: code.dbErr,
        msg: '未找到该用户'
      })
    }
    if (resFind.length === 0) {
      return socket.emit('throw err', {
        code: code.dbErr,
        msg: '未找到该用户'
      })
    }
    member[userId] = resFind[0]
    member[userId].joinTime = Date.now()
    member[userId].socketId = socket.id
    member[userId].volumeUp = false
    await redis.multi()
      .hSet(roomKey, 'member', JSON.stringify(member))
      .hSet('user' + userId,  socket.handshake.query.roomId, Date.now())
      .exec()
    const roomInfo = await redis.hGetAll(roomKey)
    socket.join(roomKey)
    console.log('加入房间', roomInfo)
    socket.emit('self join room', roomInfo)
    // 除了自己房间内的其他人都能接收到信息
    socket.to(roomKey).emit('other join room', member)    
  })()
}

module.exports = transfer
